package com.yb.login.center.provider;

import com.yb.auth.core.bean.SysUser;
import com.yb.auth.core.bean.SysUserMobileAuthentication;
import com.yb.core.constant.HttpConstant;
import com.yb.core.constant.RedisConstant;
import com.yb.core.util.DecryptUtil;
import com.yb.core.util.RedisUtil;
import com.yb.login.center.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * Copyright (C), 2022-2022, 姚兵
 * Author: 32210
 * Date: 2022/11/13 18:35
 * FileName: SysUserAuthProvider
 * Description:
 */

@Order(Ordered.HIGHEST_PRECEDENCE+1)
@Component
@Slf4j
public class SysUserMobileAuthProvider implements AuthenticationProvider {
    @Autowired
    ISysUserService sysUserService;
    @Autowired
    PasswordEncoder passwordEncoder;


    @Autowired
    DecryptUtil decryptUtil;

    @Autowired
    RedisUtil redisUtil;
    private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SysUserMobileAuthentication sysUserMobileAuthentication = (SysUserMobileAuthentication) authentication;
        String mobile = determineMobile(sysUserMobileAuthentication);
        SysUser userDetails = (SysUser) sysUserService.loadUserByMobile(mobile);
        if(Objects.isNull(userDetails)){
            throw new UsernameNotFoundException("用户不存在");
        }

        String mobileCode = redisUtil.get(String.format(RedisConstant.MOBILE_VERIFY_CODE, mobile));

        if(!StringUtils.hasText(mobileCode)){
            throw new UsernameNotFoundException(HttpConstant.Response.VERIFY_CODE_ERROR.getMsg());
        }

        if(!mobileCode.equals(sysUserMobileAuthentication.getVerifyCode())){
            throw new UsernameNotFoundException(HttpConstant.Response.VERIFY_CODE_ERROR.getMsg());
        }
        return createSuccessAuthentication(sysUserMobileAuthentication,userDetails);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return SysUserMobileAuthentication.class.isAssignableFrom(authentication);
    }
    private String determineMobile(SysUserMobileAuthentication authentication) {
        return (authentication.getMobile() == null) ? "NONE_PROVIDED" : authentication.getMobile();
    }

    protected Authentication createSuccessAuthentication(Authentication authentication,SysUser user) {
        // Ensure we return the original credentials the user supplied,
        // so subsequent attempts are successful even with encoded passwords.
        // Also ensure we return the original getDetails(), so that future
        // authentication events after cache expiry contain the details
        SysUserMobileAuthentication result = SysUserMobileAuthentication.authenticated(user, this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
        result.setDetails(authentication.getDetails());
        result.setSysUser(user);
        result.setMobile(user.getMobile());
        log.debug("Authenticated user");
        return result;
    }
}
